/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons;

import com.fasterxml.jackson.databind.JavaType;
import io.iec.edp.caf.commons.core.api.DataSerializer;
import io.iec.edp.caf.commons.wrapper.ProtobufWrapper;
import lombok.SneakyThrows;
import lombok.var;

import java.io.*;
import java.util.Base64;

/**
 * Protobuf序列化器
 */
class ProtobufSerializer implements DataSerializer {
    private final DataOutputStream out;
    private final DataInputStream in;

    public ProtobufSerializer(OutputStream outstream, InputStream inputStream){
        this.out = new DataOutputStream(outstream);
        this.in = new DataInputStream(inputStream);
    }

    @SneakyThrows
    @Override
    public void serializeToStream(Object object) {
        var bytes = serializeToByte(object);
        this.out.write(bytes);
        this.out.flush();
        this.out.close();
    }

    @Override
    public String serializeToString(Object object) {
        var bytes = serializeToByte(object);
        return Base64.getEncoder().encodeToString(bytes);
    }

    @Override
    public byte[] serializeToByte(Object object) {
        return  ProtobufUtils.serialize(object);
    }

    @Override
    public <T> T deserialize(Class<T> clazz) throws IOException {
        var bytes = getByteArray(this.in);
        return deserialize(bytes,clazz);
    }

    @Override
    public <T> T deserialize(JavaType type) throws IOException {
        throw new RuntimeException("Protobuf Serializer Not Implement This Method:deserialize(JavaType type)");
    }

    @Override
    public <T> T deserialize(Class<?> collectionClazz, Class<?>... elementClazzes) throws IOException {
        var bytes = getByteArray(this.in);
        return deserialize(bytes,collectionClazz,elementClazzes);
    }

    @Override
    public <T> T deserialize(String value, Class<T> clazz) {
        byte[] decoded = Base64.getDecoder().decode(value);
        return deserialize(decoded,clazz);
    }

    @Override
    public <T> T deserialize(String value, JavaType type) {
        throw new RuntimeException("Protobuf Serializer Not Implement This Method:deserialize(String value, JavaType type)");
    }

    @Override
    public <T> T deserialize(String value, Class<?> collectionClazz, Class<?>... elementClazzes) {
        byte[] decoded = Base64.getDecoder().decode(value);
        return deserialize(decoded,collectionClazz,elementClazzes);
    }

    @Override
    public <T> T deserialize(byte[] value, Class<T> clazz) {
        return ProtobufUtils.deserialize(value,clazz);
    }

    @Override
    public <T> T deserialize(byte[] value, JavaType type) {
        throw new RuntimeException("Protobuf Serializer Not Implement This Method:deserialize(byte[] value, JavaType type)");
    }

    @Override
    public <T> T deserialize(byte[] value, Class<?> collectionClazz, Class<?>... elementClazzes) {
        ProtobufWrapper wrapper = deserialize(value,ProtobufWrapper.class);
        return (T)wrapper.getData();
    }

    @Override
    public Object getObjectMapper() {
        throw new RuntimeException("Protobuf Serializer Not Implement This Method:getObjectMapper");
    }

    private byte[] getByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[2048];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }
}
